package com.maimang.platform.gen.util;

import com.maimang.platform.common.config.Global;
import com.maimang.platform.common.utils.DateUtils;
import com.maimang.platform.constant.Constants;
import com.maimang.platform.gen.entity.ColumnInfo;
import com.maimang.platform.gen.entity.TableInfo;
import com.maimang.platform.lang.StringUtils;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成器 工具类
 *
 * @author Rocky
 * @date 2019-05-18
 */
public class GenUtils {
	private static final Logger log = LoggerFactory.getLogger(GenUtils.class);
	/**
	 * 项目空间路径
	 */
	private static final String PROJECT_PATH = "main/java/com/maimang/platform";

	/**
	 * mybatis空间路径
	 */
	private static final String MYBATIS_PATH = "main/resources/mapper";

	/**
	 * sql文件路径
	 */
	private static final String SQL_PATH = "sql";

	/**
	 * html空间路径
	 */
	private static final String TEMPLATES_PATH = "main/resources/templates";
	private static final String PACKAGE_NAME = "com.maimang.platform";
	private static final String TABLE_PREFIX = "sys_";
	private static final String AUTO_REMOVEPRE = "true";
	private static final String author = "Rocky";

	/**
	 * 类型转换
	 */
	public static Map<String, String> javaTypeMap = new HashMap<String, String>();

	static {
		javaTypeMap.put("tinyint", "Integer");
		javaTypeMap.put("smallint", "Integer");
		javaTypeMap.put("mediumint", "Integer");
		javaTypeMap.put("int", "Integer");
		javaTypeMap.put("number", "Integer");
		javaTypeMap.put("integer", "integer");
		javaTypeMap.put("bigint", "Long");
		javaTypeMap.put("float", "Float");
		javaTypeMap.put("double", "Double");
		javaTypeMap.put("decimal", "BigDecimal");
		javaTypeMap.put("bit", "Boolean");
		javaTypeMap.put("char", "String");
		javaTypeMap.put("varchar", "String");
		javaTypeMap.put("varchar2", "String");
		javaTypeMap.put("tinytext", "String");
		javaTypeMap.put("text", "String");
		javaTypeMap.put("mediumtext", "String");
		javaTypeMap.put("longtext", "String");
		javaTypeMap.put("time", "Date");
		javaTypeMap.put("date", "Date");
		javaTypeMap.put("datetime", "Date");
		javaTypeMap.put("timestamp", "Date");
	}

	/**
	 * 生成代码
	 */
	public static void generatorCode(TableInfo table, List<ColumnInfo> columns, ZipOutputStream zip) {
		// 表名转换成Java属性名
		String className = tableToJava(table.getTableName(), Global.getTablePrefix(), Global.getAutoRemovePre());
		table.setClassName(className);
		table.setClassname(StringUtils.uncapitalize(className));
		String htmlName = tableToHtml(table.getTableName(), Global.getTablePrefix());
		table.setHtmlName(htmlName);
		// 列信息
		table.setColumns(transColums(columns));
		// 设置主键
		table.setPrimaryKey(table.getColumnsLast());
		// 初始化vm
		VelocityInitializer.initVelocity();
		// 基础包名
		String packageName = Global.getPackageName();
		// 二级模块名称
		String moduleName = Global.getModuleName();
		// 获取vm模板配置信息
		VelocityContext context = getVelocityContext(table, packageName, moduleName, Global.getAuthor());

		// 获取模板列表
		List<String> templates = getTemplates();
		for (String template : templates) {
			// 渲染模板
			StringWriter sw = new StringWriter();
			Template tpl = Velocity.getTemplate(template, Constants.UTF8);
			tpl.merge(context, sw);
			try {
				// 添加到zip
				zip.putNextEntry(new ZipEntry(getFileName(template, table, moduleName)));
				IOUtils.write(sw.toString(), zip, Constants.UTF8);
				IOUtils.closeQuietly(sw);
				zip.closeEntry();
			} catch (IOException e) {
				log.error("渲染模板失败，表名：" + table.getTableName(), e);
			}
		}
	}

	/**
	 * 设置列信息
	 */
	public static List<ColumnInfo> transColums(List<ColumnInfo> columns) {
		// 列信息
		List<ColumnInfo> columsList = new ArrayList<>();
		for (ColumnInfo column : columns) {
			// 列名转换成Java属性名
			String attrName = StringUtils.convertToCamelCase(column.getColumnName());
			column.setAttrName(attrName);
			column.setAttrname(StringUtils.uncapitalize(attrName));

			// 列的数据类型，转换成Java类型
			String attrType = javaTypeMap.get(column.getDataType());
			column.setAttrType(attrType);

			columsList.add(column);
		}
		return columsList;
	}

	/**
	 * 获取模板信息
	 *
	 * @return 模板列表
	 */
	public static VelocityContext getVelocityContext(TableInfo table, String packageName, String moduleName, String author) {
		// java对象数据传递到模板文件vm
		VelocityContext velocityContext = new VelocityContext();
		velocityContext.put("tableName", table.getTableName());
		velocityContext.put("tableComment", replaceKeyword(table.getTableComment()));
		velocityContext.put("primaryKey", table.getPrimaryKey());
		velocityContext.put("className", table.getClassName());
		velocityContext.put("classname", table.getClassname());
		velocityContext.put("columns", table.getColumns());
		velocityContext.put("package", packageName);
		velocityContext.put("moduleName", moduleName);
		velocityContext.put("author", author);
		velocityContext.put("email", Global.getEmail());
		velocityContext.put("version", Global.getVersion());
		velocityContext.put("datetime", DateUtils.getTime());
		return velocityContext;
	}

	/**
	 * 获取模板信息(java/html/xml/sql 文件)
	 *
	 * @return 模板列表
	 */
	public static List<String> getTemplates() {
		List<String> templates = new ArrayList<String>();
		templates.add("vm/java/Entity.java.vm");
		templates.add("vm/java/Mapper.java.vm");
		templates.add("vm/java/Service.java.vm");
		templates.add("vm/java/ServiceImpl.java.vm");
		templates.add("vm/java/Controller.java.vm");
		templates.add("vm/xml/Mapper.xml.vm");
		templates.add("vm/html/list.html.vm");
		templates.add("vm/html/add.html.vm");
		templates.add("vm/html/edit.html.vm");
		templates.add("vm/sql/sql.vm");
		return templates;
	}

	/**
	 * 表名转换成Java类名
	 */
	public static String tableToJava(String tableName, String tablePrefix, String autoRemovePre) {
		if (Constants.AUTO_REOMVE_PRE.equals(autoRemovePre)) {
			tableName = tableName.substring(tableName.indexOf("_") + 1);
		}
		if (StringUtils.isNotEmpty(tablePrefix) && Constants.AUTO_REOMVE_PRE.equals(autoRemovePre)) {
			tableName = tableName.replace(tablePrefix, "");
		}
		return StringUtils.convertToCamelCase(tableName);
	}

	/**
	 * 获取html文件夹名称不带表前缀
	 * @param tableName 表名
	 * @param tablePrefix 表前缀
	 * @return
	 */
	public static String tableToHtml(String tableName, String tablePrefix) {
		// 去掉表前缀
		if (StringUtils.isNotEmpty(tablePrefix)) {
			tableName = tableName.replace(tablePrefix, "");
		}
		// 表名转驼峰命名
		tableName = StringUtils.convertToCamelCase(tableName);
		// 首字母小写
		tableName = StringUtils.uncapitalize(tableName);
		return tableName;
	}

	/**
	 * 获取文件名(全路径)
	 */
	public static String getFileName(String template, TableInfo table, String moduleName) {
		// 小写类名
		String classname = table.getClassname();
		// 大写类名
		String className = table.getClassName();
		// html文件名
		String htmlName = table.getHtmlName();
		// java文件路径
		String javaPath = PROJECT_PATH + "/" + moduleName + "/";
		// mybatis xml文件路径(mapper/module/TableMapper.xml)
		String mybatisPath = MYBATIS_PATH + "/" + moduleName + "/" + className;
		// html文件路径
		String htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + htmlName;
		// sql文件路径
		String sqlPath = SQL_PATH;

		if (template.contains("Entity.java.vm")) {
			return javaPath + "entity" + "/" + className + ".java";
		}

		if (template.contains("Mapper.java.vm")) {
			return javaPath + "mapper" + "/" + className + "Mapper.java";
		}

		if (template.contains("Service.java.vm")) {
			return javaPath + "service" + "/" + className + "Service.java";
		}

		if (template.contains("ServiceImpl.java.vm")) {
			return javaPath + "service" + "/" + "/impl/" + className + "ServiceImpl.java";
		}

		if (template.contains("Controller.java.vm")) {
			return javaPath + "controller" + "/" + className + "Controller.java";
		}

		if (template.contains("Mapper.xml.vm")) {
			return mybatisPath + "Mapper.xml";
		}

		if (template.contains("list.html.vm")) {
			return htmlPath + "/" + htmlName + ".html";
		}
		if (template.contains("add.html.vm")) {
			return htmlPath + "/" + "add.html";
		}
		if (template.contains("edit.html.vm")) {
			return htmlPath + "/" + "edit.html";
		}
		if (template.contains("sql.vm")) {
			return sqlPath + "/" + classname + "Menu.sql";
		}
		return null;
	}

	public static String getBasePackage(String packageName) {
		int lastIndex = packageName.lastIndexOf(".");
		String basePackage = StringUtils.substring(packageName, 0, lastIndex);
		return basePackage;
	}

	public static String replaceKeyword(String keyword) {
		String keyName = keyword.replaceAll("(?:表|信息)", "");
		return keyName;
	}

	public static void main(String[] args) {
		System.out.println(StringUtils.convertToCamelCase("user_name"));
		System.out.println(replaceKeyword("岗位信息表"));
		System.out.println(getBasePackage("com.maimang.platform.common"));
	}
}
